home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / tcl / tcl67.lha / tcl6.7 / compat / strtod.c < prev    next >
C/C++ Source or Header  |  1993-01-22  |  6KB  |  258 lines

  1. /* 
  2.  * strtod.c --
  3.  *
  4.  *    Source code for the "strtod" library procedure.
  5.  *
  6.  * Copyright 1988-1992 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/strtod.c,v 1.2 93/01/22 15:16:57 ouster Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22.  
  23. #ifndef TRUE
  24. #define TRUE 1
  25. #define FALSE 0
  26. #endif
  27. #ifndef NULL
  28. #define NULL 0
  29. #endif
  30.  
  31. static int maxExponent = 511;    /* Largest possible base 10 exponent.  Any
  32.                  * exponent larger than this will already
  33.                  * produce underflow or overflow, so there's
  34.                  * no need to worry about additional digits.
  35.                  */
  36. static double powersOf10[] = {    /* Table giving binary powers of 10.  Entry */
  37.     10.,            /* is 10^2^i.  Used to convert decimal */
  38.     100.,            /* exponents into floating-point numbers. */
  39.     1.0e4,
  40.     1.0e8,
  41.     1.0e16,
  42.     1.0e32,
  43.     1.0e64,
  44.     1.0e128,
  45.     1.0e256
  46. };
  47.  
  48. /*
  49.  *----------------------------------------------------------------------
  50.  *
  51.  * strtod --
  52.  *
  53.  *    This procedure converts a floating-point number from an ASCII
  54.  *    decimal representation to internal double-precision format.
  55.  *
  56.  * Results:
  57.  *    The return value is the double-precision floating-point
  58.  *    representation of the characters in string.  If endPtr isn't
  59.  *    NULL, then *endPtr is filled in with the address of the
  60.  *    next character after the last one that was part of the
  61.  *    floating-point number.
  62.  *
  63.  * Side effects:
  64.  *    None.
  65.  *
  66.  *----------------------------------------------------------------------
  67.  */
  68.  
  69. double
  70. strtod(string, endPtr)
  71.     CONST char *string;        /* A decimal ASCII floating-point number,
  72.                  * optionally preceded by white space.
  73.                  * Must have form "-I.FE-X", where I is the
  74.                  * integer part of the mantissa, F is the
  75.                  * fractional part of the mantissa, and X
  76.                  * is the exponent.  Either of the signs
  77.                  * may be "+", "-", or omitted.  Either I
  78.                  * or F may be omitted, or both.  The decimal
  79.                  * point isn't necessary unless F is present.
  80.                  * The "E" may actually be an "e".  E and X
  81.                  * may both be omitted (but not just one).
  82.                  */
  83.     char **endPtr;        /* If non-NULL, store terminating character's
  84.                  * address here. */
  85. {
  86.     int sign, expSign = FALSE;
  87.     double fraction, dblExp, *d;
  88.     register CONST char *p;
  89.     register int c;
  90.     int exp = 0;        /* Exponent read from "EX" field. */
  91.     int fracExp = 0;        /* Exponent that derives from the fractional
  92.                  * part.  Under normal circumstatnces, it is
  93.                  * the negative of the number of digits in F.
  94.                  * However, if I is very long, the last digits
  95.                  * of I get dropped (otherwise a long I with a
  96.                  * large negative exponent could cause an
  97.                  * unnecessary overflow on I alone).  In this
  98.                  * case, fracExp is incremented one for each
  99.                  * dropped digit. */
  100.     int mantSize;        /* Number of digits in mantissa. */
  101.     int decPt;            /* Number of mantissa digits BEFORE decimal
  102.                  * point. */
  103.     CONST char *pExp;        /* Temporarily holds location of exponent
  104.                  * in string. */
  105.  
  106.     /*
  107.      * Strip off leading blanks and check for a sign.
  108.      */
  109.  
  110.     p = string;
  111.     while (isspace(*p)) {
  112.     p += 1;
  113.     }
  114.     if (*p == '-') {
  115.     sign = TRUE;
  116.     p += 1;
  117.     } else {
  118.     if (*p == '+') {
  119.         p += 1;
  120.     }
  121.     sign = FALSE;
  122.     }
  123.  
  124.     /*
  125.      * Count the number of digits in the mantissa (including the decimal
  126.      * point), and also locate the decimal point.
  127.      */
  128.  
  129.     decPt = -1;
  130.     for (mantSize = 0; ; mantSize += 1)
  131.     {
  132.     c = *p;
  133.     if (!isdigit(c)) {
  134.         if ((c != '.') || (decPt >= 0)) {
  135.         break;
  136.         }
  137.         decPt = mantSize;
  138.     }
  139.     p += 1;
  140.     }
  141.  
  142.     /*
  143.      * Now suck up the digits in the mantissa.  Use two integers to
  144.      * collect 9 digits each (this is faster than using floating-point).
  145.      * If the mantissa has more than 18 digits, ignore the extras, since
  146.      * they can't affect the value anyway.
  147.      */
  148.     
  149.     pExp  = p;
  150.     p -= mantSize;
  151.     if (decPt < 0) {
  152.     decPt = mantSize;
  153.     } else {
  154.     mantSize -= 1;            /* One of the digits was the point. */
  155.     }
  156.     if (mantSize > 18) {
  157.     fracExp = decPt - 18;
  158.     mantSize = 18;
  159.     } else {
  160.     fracExp = decPt - mantSize;
  161.     }
  162.     if (mantSize == 0) {
  163.     fraction = 0.0;
  164.     p = string;
  165.     goto done;
  166.     } else {
  167.     int frac1, frac2;
  168.     frac1 = 0;
  169.     for ( ; mantSize > 9; mantSize -= 1)
  170.     {
  171.         c = *p;
  172.         p += 1;
  173.         if (c == '.') {
  174.         c = *p;
  175.         p += 1;
  176.         }
  177.         frac1 = 10*frac1 + (c - '0');
  178.     }
  179.     frac2 = 0;
  180.     for (; mantSize > 0; mantSize -= 1)
  181.     {
  182.         c = *p;
  183.         p += 1;
  184.         if (c == '.') {
  185.         c = *p;
  186.         p += 1;
  187.         }
  188.         frac2 = 10*frac2 + (c - '0');
  189.     }
  190.     fraction = (1.0e9 * frac1) + frac2;
  191.     }
  192.  
  193.     /*
  194.      * Skim off the exponent.
  195.      */
  196.  
  197.     p = pExp;
  198.     if ((*p == 'E') || (*p == 'e')) {
  199.     p += 1;
  200.     if (*p == '-') {
  201.         expSign = TRUE;
  202.         p += 1;
  203.     } else {
  204.         if (*p == '+') {
  205.         p += 1;
  206.         }
  207.         expSign = FALSE;
  208.     }
  209.     while (isdigit(*p)) {
  210.         exp = exp * 10 + (*p - '0');
  211.         p += 1;
  212.     }
  213.     }
  214.     if (expSign) {
  215.     exp = fracExp - exp;
  216.     } else {
  217.     exp = fracExp + exp;
  218.     }
  219.  
  220.     /*
  221.      * Generate a floating-point number that represents the exponent.
  222.      * Do this by processing the exponent one bit at a time to combine
  223.      * many powers of 2 of 10. Then combine the exponent with the
  224.      * fraction.
  225.      */
  226.     
  227.     if (exp < 0) {
  228.     expSign = TRUE;
  229.     exp = -exp;
  230.     } else {
  231.     expSign = FALSE;
  232.     }
  233.     if (exp > maxExponent) {
  234.     exp = maxExponent;
  235.     }
  236.     dblExp = 1.0;
  237.     for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
  238.     if (exp & 01) {
  239.         dblExp *= *d;
  240.     }
  241.     }
  242.     if (expSign) {
  243.     fraction /= dblExp;
  244.     } else {
  245.     fraction *= dblExp;
  246.     }
  247.  
  248. done:
  249.     if (endPtr != NULL) {
  250.     *endPtr = (char *) p;
  251.     }
  252.  
  253.     if (sign) {
  254.     return -fraction;
  255.     }
  256.     return fraction;
  257. }
  258.